﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace Cid.Mvc.Windows.Controls
{

	using Cid.Models;
	using Cid.Models.Validation;
	using System.Reflection;
	using System.Data.Linq.Mapping;
	/// <summary>
	/// Interaction logic for DetailsView.xaml
	/// </summary>
	public partial class DetailsView : UserControl
	{
		private TextBlock textBlock;
		private Button save;
		private Button cancel;
		private Button createNew;
		private bool showSave = true;
		private bool showInsert = true;
		private bool showCancel = false;

		public DetailsView()
		{
			InitializeComponent();
		}

		public bool ShowSave
		{
			get
			{
				return this.showSave;
			}
			set
			{
				if (this.save != null)
					this.save.Visibility = value ? Visibility.Visible : Visibility.Collapsed;
				this.showSave = value;
			}
		}

		public bool ShowInsert
		{
			get
			{
				return this.showInsert;
			}
			set
			{
				if (this.createNew != null)
					this.createNew.Visibility = value ? Visibility.Visible : Visibility.Collapsed;
				this.showInsert = value;
			}
		}

		public bool ShowCancel
		{
			get
			{
				return this.showCancel;
			}
			set
			{
				if (this.cancel != null)
					this.cancel.Visibility = value ? Visibility.Visible : Visibility.Collapsed;
				this.showCancel = value;
			}
		}

	
		public event RoutedEventHandler Saved
		{
			add { this.save.Click += value; }
			remove { this.save.Click -= value; }
		}

		public event RoutedEventHandler Canceled
		{
			add { this.cancel.Click += value; }
			remove { this.cancel.Click -= value; }
		}

		public event RoutedEventHandler Insert
		{
			add { this.createNew.Click += value; }
			remove { this.createNew.Click -= value; }
		}

		public event RoutedEventHandler DataContextChanged;


		public string Message
		{
			get { return this.textBlock.Text; }
			set { this.textBlock.Text = value;}
		}

		public Brush MessageBrush
		{
			get { return this.textBlock.Foreground; }
			set { this.textBlock.Foreground = value; }
		}

		protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
		{
			base.OnPropertyChanged(e);
			base.OnPropertyChanged(e);
			if (e.Property.Name == "DataContext")
			{

				if (e.NewValue != null) {
					if(e.NewValue is IBase)
						this.Bind((IBase)e.NewValue);
				}
			}

			RoutedEventHandler eh = this.DataContextChanged;
			if (eh != null)
				eh(this, new RoutedEventArgs());
		}


		public void Bind(IBase entity)
		{
			this.Grid.Children.Clear();
			this.Grid.ColumnDefinitions.Clear();
			this.Grid.RowDefinitions.Clear();

			Type type = entity.GetType();
			PropertyInfo[] properties = type.GetProperties();
			this.CreateColumns();
			this.CreateMessageRow();

			foreach (PropertyInfo property in properties)
			{
				object[] items = property.GetCustomAttributes(typeof(ColumnAttribute), true);
				ColumnAttribute attr = (items.FirstOrDefault() as ColumnAttribute);
				if (attr != null && !attr.IsPrimaryKey && property.CanWrite)
				{
					if (property.PropertyType.IsGenericType && property.PropertyType.GetGenericArguments().Count() == 1)
						this.CreateRow(entity, property.Name, property.PropertyType.GetGenericArguments()[0], attr.DbType);
					else
						this.CreateRow(entity, property.Name, property.PropertyType, attr.DbType);


				}
			}

			this.CreateSaveCancelButtons();
		}

		private void CreateColumns()
		{
			this.Grid.ColumnDefinitions.Add(
				new ColumnDefinition()
				{
					Name = "Label",
					MaxWidth = 100
				});

			this.Grid.ColumnDefinitions.Add(
				new ColumnDefinition()
				{
					Name = "Data",
					
				});

			this.Grid.ColumnDefinitions.Add(
				new ColumnDefinition()
				{
					Name = "Meta",
					MaxWidth = 100
				});
		}

		private void CreateMessageRow()
		{
			int index = this.Grid.RowDefinitions.Count;
			this.Grid.RowDefinitions.Add(new RowDefinition() { Height = GridLength.Auto, Name = "Row{0}".Fuse(index) });

			this.textBlock = new TextBlock();
			this.textBlock.SetValue(Grid.ColumnSpanProperty, 3);
			this.textBlock.SetValue(Grid.RowProperty, 0);
			this.Grid.Children.Add(this.textBlock);
		}

		private void CreateSaveCancelButtons()
		{
			int index = this.Grid.RowDefinitions.Count;
			this.Grid.RowDefinitions.Add(new RowDefinition() { Height = GridLength.Auto, Name = "Row{0}".Fuse(index) });

			DockPanel panel = new DockPanel();
			panel.SetValue(Grid.ColumnProperty, 1);
			panel.SetValue(Grid.RowProperty, index);
			this.Grid.Children.Add(panel);

			this.createNew = new Button();
			this.createNew.Content = "New";
			this.createNew.Width = 60;
			this.createNew.MaxHeight = 40;
			this.createNew.Margin = new Thickness(5);
			this.ShowInsert = this.showInsert;
			panel.Children.Add(this.createNew);

			this.save = new Button();
			this.save.Content = "Save";
			this.save.Width = 60;
			this.save.MaxHeight = 40;
			this.save.Margin = new Thickness(5);
			this.ShowSave = this.showSave;
			panel.Children.Add(this.save);

			

			this.cancel = new Button();
			this.cancel.Content = "Cancel";
			this.cancel.Width = 60;
			this.cancel.MaxHeight = 40;
			this.cancel.Margin = new Thickness(5);
			this.ShowCancel = this.showCancel;
			panel.Children.Add(this.cancel);
		}


		private void CreateRow(object entity, string propertyName, Type type, string dbType)
		{
			int index = this.Grid.RowDefinitions.Count;
			this.Grid.RowDefinitions.Add(new RowDefinition() { Height = GridLength.Auto, Name = "Row{0}".Fuse(index) });

			System.Windows.Controls.Label label = new System.Windows.Controls.Label();
			label.Content = propertyName.Titlize();
			label.SetValue(Grid.ColumnProperty, 0);
			label.SetValue(Grid.RowProperty, index);

			Binding binding = new Binding(propertyName)
			{
				Mode = BindingMode.TwoWay,
				Source = entity
			};

			if (entity is IValidatorErrorInfo)
			{
				binding.UpdateSourceTrigger = UpdateSourceTrigger.LostFocus;
					
				binding.ValidationRules.Add(
					new Cid.Windows.Controls.ObjectValidationRules(){
						Rules = ((IValidatorErrorInfo)entity)[propertyName]
					});
			}


			this.Grid.Children.Add(label);

			switch (type.ToString())
			{
				case "System.String":
					TextBox box = new TextBox();
					box.SetValue(Grid.RowProperty, index);
					box.SetValue(Grid.ColumnProperty, 1);
					if (!string.IsNullOrEmpty(dbType) && dbType.ToLower().Contains("text"))
						box.MinLines = 5;
					else
						box.MinLines = 1;

					//box.BorderBrush = Brushes.Green;
					//box.BorderThickness = new Thickness(1);

					box.SetBinding(TextBox.TextProperty, binding);
					this.Grid.Children.Add(box);

					//AdornedElementPlaceholder ph = new AdornedElementPlaceholder();
					//ph.SetValue(Grid.ColumnProperty, 2);
					//ph.SetValue(Grid.RowProperty, index);
					//ph.Name = propertyName + "Val";
					//this.Grid.Children.Add(ph);

					//box.SetBinding(TextBox.ToolTipProperty,
					//    new Binding("AdornedElement.(Validation.Errors)[0].ErrorContent")
					//    {
					//        ElementName = propertyName + "Val"
					//    });

					break;
				case "System.DateTime":
					TextBox box2 = new TextBox();
					box2.SetValue(Grid.RowProperty, index);
					box2.SetValue(Grid.ColumnProperty, 1);
					//box2.BorderBrush = Brushes.Green;
					//box2.BorderThickness = new Thickness(1);
					
					binding.Converter = new Cid.Windows.NullableDateTimeConverter();
					//binding.Converter = (IValueConverter)new DateTimeConverter();
					box2.SetBinding(TextBox.TextProperty, binding);
					this.Grid.Children.Add(box2);

					//AdornedElementPlaceholder ph2 = new AdornedElementPlaceholder();
					//ph2.SetValue(Grid.ColumnProperty, 2);
					//ph2.SetValue(Grid.RowProperty, index);
					//ph2.Name = propertyName + "Val";
					//this.Grid.Children.Add(ph2);

					//box2.SetBinding(TextBox.ToolTipProperty,
					//    new Binding("AdornedElement.(Validation.Errors)[0].ErrorContent")
					//    {
					//        ElementName = propertyName + "Val"
					//    });

					break;
			}

			
		}

	}
}
